﻿using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using AuthClientApi.Helpers;
using Microsoft.AspNetCore.Authentication.OAuth;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Caching.Memory;
using Newtonsoft.Json;

namespace AuthClientApi.Controllers
{
    [ApiController]
    public class AuthenticationController : ControllerBase
    {
        private readonly IMemoryCache _memoryCache;
        private readonly OpenidConfiguration _openidConfiguration;

        public AuthenticationController(IMemoryCache  memoryCache, OpenidConfiguration openidConfiguration)
        {
            _memoryCache = memoryCache;
            _openidConfiguration = openidConfiguration;
        }
        [HttpGet("~/getLoginUri")]
        public Task<object> GetTestUri()
        {
            string state = "8_LrjUb4I0tNSCkAFfmPTekJkAd-wWkdtwYcCb3hQ4I";
            var parameters = new Dictionary<string, string>
            {
                { "client_id", "mvc3" },
                { "redirect_uri", "https://localhost:44338/callback/login/local" },
                { "response_type", "code" },
                { "scope", "openid email profile" },
                { "nonce", "AHzTm2qQkn7jXl1sf_soyhzgcwPX5u9puTBHPXU8y4Y" },
                { "state", state }
            };
            var bytes = new byte[32];
            RandomNumberGenerator.Fill(bytes);
            var codeVerifier = Microsoft.AspNetCore.Authentication.Base64UrlTextEncoder.Encode(bytes);
            _memoryCache.Set($"CodeVerifier_{state}", codeVerifier);
            var challengeBytes = SHA256.HashData(Encoding.UTF8.GetBytes(codeVerifier));
            var codeChallenge = WebEncoders.Base64UrlEncode(challengeBytes);

            parameters[OAuthConstants.CodeChallengeKey] = codeChallenge;
            parameters[OAuthConstants.CodeChallengeMethodKey] = OAuthConstants.CodeChallengeMethodS256;
            var uri = QueryHelpers.AddQueryString(_openidConfiguration.authorization_endpoint, parameters!);
            return Task.FromResult<object>(new
            {
                uri,
                codeVerifier
            });
        }
        /// <summary>
        /// 回调
        /// </summary>
        /// <returns></returns>
        [HttpGet("~/callback/login/{provider}"), HttpPost("~/callback/login/{provider}"), IgnoreAntiforgeryToken]
        public async Task<IActionResult?> CallBack()
        {
            var query = HttpContext.Request.Query;
            var code = query["code"].ToString();
            var state = query["state"].ToString();
            var codeVerifierCache = _memoryCache.Get<string>($"CodeVerifier_{state}");
            if (string.IsNullOrEmpty(codeVerifierCache))
            {
                await HttpContext.Response.WriteAsync("error");
                return null;
            }
            var parameters = new Dictionary<string, string>
            {
                {"grant_type","authorization_code"},
                {"code",code},
                {"code_verifier",codeVerifierCache},
                {"redirect_uri","https://localhost:44338/callback/login/local"},
                { "client_id", "mvc3" },
                { "client_secret", "901564A5-E7FE-42CB-B10D-61EF6A8F3654" }
            };
            StringBuilder stringBuilder = new StringBuilder();
            foreach (var kvp in parameters)
            {
                stringBuilder.Append(Uri.EscapeDataString(kvp.Key));
                stringBuilder.Append("=");
                stringBuilder.Append(Uri.EscapeDataString(kvp.Value));
                stringBuilder.Append("&");
            }
            string body = stringBuilder.ToString().TrimEnd('&');
            var token = await HttpHelper.PostAsync(_openidConfiguration.token_endpoint, body, null, content =>
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
            });
            var tokenModel = JsonConvert.DeserializeObject<Rootobject>(token);
            _memoryCache.Set($"OAuthToken_{tokenModel!.id_token.GetHashCode()}", tokenModel);
            _memoryCache.Remove($"CodeVerifier_{state}");
            Console.WriteLine(token);
            //return Redirect("https://www.cnblogs.com/");
            return Ok("授权成功");
        }
    }
}